﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Tsual.Wechat;
using Tsual.Wechat.Cache;
using Tsual.Wechat.Message.Exceptions;
using Tsual.Util;
using Tsual.Wechat.Message.Interface.Request;
using Tsual.Wechat.Message.Interface.Response;
using Tsual.Wechat.Message.Impl.Response;
using Tsual.Wechat.Message;
using Tsual.Wechat.Message.Impl;
using Microsoft.Extensions.Configuration;
using StackExchange.Redis;
using Tsual.Util.Redis;
using Microsoft.AspNetCore.Identity;
using System.Net.Http;
using Tsual.Wechat.Filters;
using Tsual.Wechat.Backgroud;
using RedLockNet.SERedis;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Tsual.Wechat.Pipes;
using System.IO;
using Tsual.DataPipeline;

namespace wechat_service.Controllers
{
    public abstract class AbstractWechatController : Controller
    {
        protected ILogger<AbstractWechatController> logger;
        protected IServiceProvider serviceProvider;
        protected IDatabase cache;
        protected IHttpClientFactory httpClientFactory;
        protected IHostingEnvironment environment;

        protected AbstractWechatController(ILogger<AbstractWechatController> logger, IServiceProvider serviceProvider, IDatabase cache, IHttpClientFactory httpClientFactory, IHostingEnvironment environment)
        {
            this.logger = logger;
            this.serviceProvider = serviceProvider;
            this.cache = cache;
            this.httpClientFactory = httpClientFactory;
            this.environment = environment;
        }

        protected async Task<IActionResult> dealPageCodeAsync(Func<IActionResult> func,string code,string state)
        {
            var key = WechatCacheKeyEnum.USER_ACCESS_PAGE_CODE.ToRedisKey();
            var weekLockContent = cache.HashGetExp(key, code);
            try
            {
                if (string.IsNullOrEmpty(weekLockContent) && "{}" != weekLockContent)
                {
                    cache.HashSet(key, code, "{}");
                    var uat = await WechatContext.Instance.GetUserAccessTokenAsync(pageCode: code);
                    using (var fs = System.IO.File.Open($"uat-{DateTime.Now.Ticks}.json", System.IO.FileMode.Create))
                    using (var sw = new StreamWriter(fs))
                    {
                        sw.Write(JsonConvert.SerializeObject(uat));
                        sw.Flush();
                    }

                    if (environment.IsDevelopment())
                        cache.HashSet(key, code, JsonConvert.SerializeObject(uat));
                    else
                        cache.HashSet(key, code, JsonConvert.SerializeObject(uat), TimeSpan.FromMinutes(5));
                    ViewData["openid"] = uat.openid;
                    ViewData["uat"] = uat;
                }
                else
                {
                    var uatm = JsonConvert.DeserializeObject<WsrmUserAccessToken>(weekLockContent);
                    ViewData["openid"] = uatm.openid;
                    ViewData["uat"] = uatm.access_token;
                }

                return func();
            }
            catch (WechatApiException ex)
            {
                if (ex.Response.errcode == 40163)
                {
                    //处理缓存过期
                    ViewData["errorMessage"] = "页面已经过期,需要刷新";
                    return View("error");
                }
                else
                {
                    throw ex;
                }
            }
        }
    }



    [Route("wechat")]
    public class WechatController : AbstractWechatController
    {
        IConfiguration configuration;
        AppDbContext db;
        UserManager<AppIdentityUser> userManager;
        PmouldWechatCore coreMould;

        public WechatController(ILogger<AbstractWechatController> logger, IServiceProvider serviceProvider, IDatabase cache, IHttpClientFactory httpClientFactory, IHostingEnvironment environment, IConfiguration configuration, AppDbContext db, UserManager<AppIdentityUser> userManager, PmouldWechatCore coreMould) : base(logger, serviceProvider, cache, httpClientFactory, environment)
        {
            this.configuration = configuration;
            this.db = db;
            this.userManager = userManager;
            this.coreMould = coreMould;
        }

        private string FindUseridByOpenidOrRefreshDb(string openId) => coreMould.KnownUsers.ReadAsync(new DpmmKnownUser(openId)).GetAwaiter().GetResult().Data;

        //https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
        [Route("innerlg")]
        public IActionResult WechatInnerLogin()
        {
            logger?.LogTrace("收到微信绑定请求，正在重定向到微信授权...");
            return Redirect(NetExtensions.UrlAppendParam(@"https://open.weixin.qq.com/connect/oauth2/authorize", args: new Dictionary<string, string>() {
                {"appid", configuration["Wechat:AppId"]},
                {"redirect_uri",string.Format("{0}://{1}/wechat/innerlgchkd",Request.Scheme,Request.Host)},
                {"response_type","code" },
                {"scope","snsapi_userinfo" },
                {"state", "0"}
            }.ToArray()) + @"#wechat_redirect");
        }

        //http://localhost/wechat/innerlgchkd?code=011cigEf23wo3J0QJzBf236eEf2cigEt&state=0&nsukey=asG833Az6%2FuPsCYqIpxu6oXqmMwdDphSo6bjeepKp4h0t2cFetuiAm3qjOg0xQ06UwFuli18j8ntDa1DoaNfcqnk4gwEPfLLBKb6zx%2BuGhbthHmz0O3If4DLWf5aXQv4k2EzpkXaTdl1jhlpi6YIMFxG5%2FpodbT1%2FcUC9OnGLTM%3D
        [Route("innerlgchkd")]
        public async Task<IActionResult> WechatInnerLoginCheckedAsync(string code, string state)
        {
            var tl = coreMould.UserAccessToken.ReadAsync(new DpmmUserAccessToken(code, null), ignoreReadError: false);
            try
            {
                var uat = (await tl).GetResultOrThrowException();
                logger.LogTrace(JsonConvert.SerializeObject(tl.Result));
                var uid = FindUseridByOpenidOrRefreshDb(uat.openid);
                logger.LogTrace(uid);
                var user = db.Users.Find(uid);
                if (string.IsNullOrEmpty(uid))
                {
                    return View("wlb");
                }
                else
                {
                    ViewData["Title"] = "已完成绑定😘";
                    ViewData["message"] = $"该账号已经绑定至用户 {user.UserName}";
                    return View("success");
                }
            }
            catch(Exception ex)
            {
                logger.LogError(ex, "exxxxxxxx");
                ViewData["errorMessage"] = ex.Message;
                return View("error");
            }finally
            {
                using (var fs = System.IO.File.Open($"uat-{DateTime.Now.Ticks}.json", System.IO.FileMode.Create))
                using (var sw = new StreamWriter(fs))
                {
                    sw.Write(JsonConvert.SerializeObject(tl.Result));
                    sw.Flush();
                }
            }

        }
        //=> await dealPageCodeAsync(() =>
        // {
        //     var uid = FindUseridByOpenidOrRefreshDb((string)ViewData["openid"]);
        //     if (string.IsNullOrEmpty(uid))
        //     {
        //         return View("wlb");
        //     }
        //     else
        //     {
        //         ViewData["Title"] = "已完成绑定😘";
        //         ViewData["message"] = $"该账号已经绑定至用户 {db.Users.Find(uid).UserName}";
        //         return View("success");
        //     }
        // }, code, state);

        [ValidateAntiForgeryToken]
        [HttpPost("pb")]
        public async Task<IActionResult> PostBindAsync(PostBindModel postBindModel)
        {
            var user = await userManager.FindByNameAsync(postBindModel.userName);
            if (user != null)
            {
                if (await userManager.CheckPasswordAsync(user, postBindModel.password))
                {
                    user.WechatOpenid = postBindModel.openId;
                    db.Entry(user).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                    await db.SaveChangesAsync();
                    cache.HashSet(WechatCacheKeyEnum.USER_KNOWN.ToRedisKey(), user.WechatOpenid, user.Id);
                    ViewData["Title"] = "已完成绑定😘";
                    ViewData["message"] = $"该账号已经绑定至用户 {user.UserName}";
                    return View("success");
                }
                ViewData["errorMessage"] = "密码不正确";
                return View("error");
            }
            ViewData["errorMessage"] = "用户不存在";
            return View("error");
        }

        public class PostBindModel
        {
            public string openId { get; set; }
            public string userName { get; set; }
            public string password { get; set; }
        }

        [Route("cfgwarn")]
        public IActionResult cfgwarn()
        {
            logger?.LogTrace("收到微信绑定请求，正在重定向到微信授权...");
            return Redirect(NetExtensions.UrlAppendParam(@"https://open.weixin.qq.com/connect/oauth2/authorize", args: new Dictionary<string, string>() {
                {"appid", configuration["Wechat:AppId"]},
                {"redirect_uri",string.Format("{0}://{1}/wechat/cfgwarnchkd",Request.Scheme,Request.Host)},
                {"response_type","code" },
                {"scope","snsapi_userinfo" },
                {"state", "0"}
            }.ToArray()) + @"#wechat_redirect");
        }

        
        [Route("cfgwarnchkd")]
        public async Task<IActionResult> cfgwarnchkdAsync(string code, string state)
            => await dealPageCodeAsync(() =>
            {
                var uid = FindUseridByOpenidOrRefreshDb((string)ViewData["openid"]);
                if (string.IsNullOrEmpty(uid))
                {
                    ViewData["errorMessage"] = "需要先绑定本平台";
                    return View("error");
                }
                else
                {
                    return View("cfgwarnchkd");
                }
            }, code, state);

        public class WarningCfgPostModel
        {
            public string enable { get; set; }
        }

        [HttpPost("PostCfg")]
        public IActionResult PostCfg(WarningCfgPostModel model)
        {
            ViewData["Title"] = "配置更新成功";
            ViewData["message"] = model.enable == "on" ? "已启用告警推送":"已禁用告警推送";
            return View("success");
        }

        [Route("eqstate")]
        public IActionResult eqstate()
        {
            ViewData["Title"] = "正在开发中...";
            ViewData["message"] = "功能正在开发中...";
            return View("info");
        }

        [Route("prodstate")]
        public IActionResult prodstate()
        {
            ViewData["Title"] = "正在开发中...";
            ViewData["message"] = "功能正在开发中...";
            return View("info");
        }
    }

    [HandlerPrivilege(WechatMessageHandlerPrivilege.VeryLow)]
    public class EchoWechatText : IWechatMessageHandler<IWechatRequestText>
    {
        public bool CanHandle(IWechatRequestText RequestMessageModel) => true;
        public WechatMessageHandleResult Handle(IWechatRequestText RequestMessageModel)
            => WechatMessageHandleResult.Sucess(new WechatResponseText()
            {
                Content = RequestMessageModel.Content,
                CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds()),
                FromUserName = RequestMessageModel.ToUserName,
                ToUserName = RequestMessageModel.FromUserName
            });
    }

    public class AutoRegistWechatText : IWechatMessageHandler<IWechatRequestText>
    {
        AppDbContext db;
        UserManager<AppIdentityUser> userManager;
        IDatabase cache;
        PmouldWechatCore coreMould;

        public AutoRegistWechatText(AppDbContext db, UserManager<AppIdentityUser> userManager, IDatabase cache, PmouldWechatCore coreMould)
        {
            this.db = db;
            this.userManager = userManager;
            this.cache = cache;
            this.coreMould = coreMould;
        }

        public bool CanHandle(IWechatRequestText RequestMessageModel)
        {
            return RequestMessageModel.Content == "自动注册";
        }

        public WechatMessageHandleResult Handle(IWechatRequestText RequestMessageModel)
        {
            if (db.Users.Where(t => t.WechatOpenid == RequestMessageModel.FromUserName).Count() > 0)
                return WechatMessageHandleResult.Sucess(new WechatResponseText()
                {
                    Content = "已经注册或绑定",
                    CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds()),
                    FromUserName = RequestMessageModel.ToUserName,
                    ToUserName = RequestMessageModel.FromUserName
                });

            Random random = new Random();
            short username = Convert.ToInt16(random.Next(short.MaxValue));
            {
                int max = 10;
                while (max-- > 0 && db.Users.Where(t => t.UserName == username.ToString()).Count() > 0)
                {
                    username = Convert.ToInt16(random.Next(short.MaxValue));
                }
            }
            var pwd_byte = new byte[16];
            random.NextBytes(pwd_byte);
            var pwd = Convert.ToBase64String(pwd_byte);
            var result = userManager.CreateAsync(new AppIdentityUser() { UserName = username.ToString()}, pwd).GetAwaiter().GetResult();

            coreMould.KnownUsers.WriteAsync(db.Users.Where(t => t.Id == username.ToString()).Select(t => t.Id).FirstOrDefault(), new DpmmKnownUser(RequestMessageModel.FromUserName)).Wait();
            return WechatMessageHandleResult.Sucess(new WechatResponseText()
            {
                Content = "用户名:" + username + "\n密码:" + pwd,
                CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds()),
                FromUserName = RequestMessageModel.ToUserName,
                ToUserName = RequestMessageModel.FromUserName
            });
        }
    }

    public class HelloHandler : IWechatMessageHandler<IWechatRequestEvent>
    {
        AppDbContext db;
        IDatabase cache;

        public HelloHandler(AppDbContext db, IDatabase cache)
        {
            this.db = db;
            db.Database.EnsureCreated();
            this.cache = cache;
        }

        public bool CanHandle(IWechatRequestEvent RequestMessageModel) => RequestMessageModel.Event == "subscribe";

        public WechatMessageHandleResult Handle(IWechatRequestEvent RequestMessageModel)
        {
            string uid;

            if (!string.IsNullOrEmpty(uid = cache.HashGet(WechatCacheKeyEnum.USER_KNOWN.ToRedisKey(), RequestMessageModel.FromUserName)))
            {
                return WechatMessageHandleResult.Sucess(new WechatResponseText()
                {
                    Content = "欢迎回来," + db.Users.Find(uid).UserName,
                    CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds()),
                    FromUserName = RequestMessageModel.ToUserName,
                    ToUserName = RequestMessageModel.FromUserName
                });
            }
            else if (db.Users.Where(t => t.WechatOpenid == RequestMessageModel.FromUserName).Count() > 0)
            {
                return WechatMessageHandleResult.Sucess(new WechatResponseText()
                {
                    Content = "欢迎回来," + db.Users.Where(t => t.WechatOpenid == RequestMessageModel.FromUserName).FirstOrDefault().UserName,
                    CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds()),
                    FromUserName = RequestMessageModel.ToUserName,
                    ToUserName = RequestMessageModel.FromUserName
                });
            }
            else
            {
                return WechatMessageHandleResult.Sucess(new WechatResponseText()
                {
                    Content = "谢谢关注本公众号，您的账号尚未绑定，请先绑定",
                    CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds()),
                    FromUserName = RequestMessageModel.ToUserName,
                    ToUserName = RequestMessageModel.FromUserName
                });
            }
        }
    }

    public class PsHandler : IWechatMessageHandler<IWechatRequestEvent>
    {
        public bool CanHandle(IWechatRequestEvent RequestMessageModel) => RequestMessageModel.Event == "CLICK" && RequestMessageModel.EventKey == "WECHAT_MENU_PRODUCT_STATUS";

        public WechatMessageHandleResult Handle(IWechatRequestEvent RequestMessageModel) => WechatMessageHandleResult.Sucess(new WechatResponseText()
        {
            Content = "test message 4 production status",
            CreateTime = Convert.ToInt32(DateTimeOffset.Now.ToUnixTimeSeconds()),
            FromUserName = RequestMessageModel.ToUserName,
            ToUserName = RequestMessageModel.FromUserName
        });
            
            
    }

    public class DsHandler : IWechatMessageHandler<IWechatRequestEvent>
    {
        public bool CanHandle(IWechatRequestEvent RequestMessageModel) => RequestMessageModel.Event == "CLICK" && RequestMessageModel.EventKey == "WECHAT_MENU_DEVICE_STATUS";

        public WechatMessageHandleResult Handle(IWechatRequestEvent RequestMessageModel) => WechatMessageHandleResult.Sucess(new WechatResponseText()
        {
            Content = "test message 4 device status",
            CreateTime = Convert.ToInt32(DateTimeOffset.Now.ToUnixTimeSeconds()),
            FromUserName = RequestMessageModel.ToUserName,
            ToUserName = RequestMessageModel.FromUserName
        });


    }

    public class MTtest : IWechatMessageHandler<IWechatRequestText>
    {
        PmouldWechatTemplate mould;

        public MTtest(PmouldWechatTemplate mould)
        {
            this.mould = mould;
        }

        public bool CanHandle(IWechatRequestText RequestMessageModel) => RequestMessageModel.Content == "测试模板";

        public WechatMessageHandleResult Handle(IWechatRequestText RequestMessageModel)
        {
            mould.SendTemplate.WriteAsync(new WssmTemplateSend()
            {
                touser = RequestMessageModel.FromUserName,
                url = "www.baidu.com",
                template_id = "jK5wOW9ruWYIOTuukKUvQIz-DdGrWlerprr-_t_IUZI",
                data = new Dictionary<string, WssmTemplateSendItem>()
                {
                    //{"first",new WssmTemplateSendItem(){ value="您配置的设备发出告警！" } },
                    {"keyword1",new WssmTemplateSendItem (){ value ="00180501778C"} },
                    {"keyword2",new WssmTemplateSendItem(){ value=DateTime.Now.ToString()} },
                    {"keyword3",new WssmTemplateSendItem(){ value ="123"} },
                    {"keyword4",new WssmTemplateSendItem(){ value = "123"}  },
                    //{"remark",new WssmTemplateSendItem(){ value ="请尽快处理！"} }
                }
            }, DpmmSendTemplate.Instance).Wait();
            return null;
        }
    }
}
